#include "Wizard.h"
#include <iomanip>

Wizard::Wizard(std::string name, std::string race, bool is_male, bool hostile, Progress::ach killAch, int voice_pitch, int level, int exp_since_level_up):
Character(name,race, is_male,killAch,voice_pitch, level, exp_since_level_up, hostile)
{
	setInitialAttributes();
	addExperience(exp, false);
}

void Wizard::sleep(){
	HP = getMaxHP();
	mana = getMaxMana();
	speak("I have slept well. I recovered my health and mana.", this);
}

void Wizard::gather(bool mana){
	int gathered = ((getConsumption(true)*2) - 5);
	std::string say = name;
	say += " gathered ";
	say += std::to_string(gathered);
	say += " mana points.";
	speak(say);
	updateMana(gathered);
}

int Wizard::getConsumption(bool mag){
		return getMag()/2;
}

int Wizard::doAttack(bool mag){
	if(getMana() - getConsumption(true) < 0){
			speak("I do not have enough mana to attack", this);
			return -1;
	}
	updateMana(-getConsumption(true));
	return (getMag() + (((rand()%(getMag()*2)) - getMag()) % getMag()/4)); 
}

int Wizard::attackPossible(){
	std::vector<int> type;
	if(getMana() - getConsumption(true) > 0){
		type.push_back(2);
	}
	if(type.size() == 0){
		type.push_back(3);
	}
	return type[rand() % type.size()];
}

void Wizard::getStatus(){
	std::string say = name;
	say += " have ";
	say += std::to_string(getHP());
	say += " health points and ";
	say += std::to_string(getMana());
	say += " mana points."; 
	speak(say);
}


void Wizard::getStatusAllAttributes(){
	std::stringstream ss;
	std::string say = name;
	say += " are a ";
	if(male){
		say += "male ";
	}
	else{
		say += "female ";
	}
	say += race;
	say += " wizard.";
	say += "\n";
	
	say += name;
	say += " have ";
	say += std::to_string(exp);
	say += " experience and are at level ";
	say += std::to_string(level);
	say += ".\n";
	say += name;
	say += " have:\n";
	
	ss << say;
	std::string hpstring = (std::to_string(getHP()) + " health points");
	size_t width = hpstring.size() +1;
	std::string manastring = (std::to_string(getMana()) + " mana points");
	if(width < manastring.size() + 1){ width = manastring.size() +1; }
	std::string defstring = (std::to_string(getDef()) + " defence points");
	if(width < defstring.size() + 1){ width = defstring.size() +1; }
	std::string magstring = (std::to_string(getMag()) + " magical attack points");
	if(width < magstring.size() + 1){ width = magstring.size() +1; }

	
	
	ss << std::left << std::setw(width) << hpstring << "|\t" << std::to_string(getMaxHP()) << " maximum health points" << std::endl;
	ss << std::left << std::setw(width) << manastring << "|\t" << std::to_string(getMaxMana()) << " maximum mana points" << std::endl;
	ss << std::left << std::setw(width) << defstring << "|\t" << std::to_string(getMagDef()) << " magical defence points" << std::endl;
	ss << std::left << std::setw(width) << magstring << "|" << std::endl;
	speak(ss.str());
}


std::vector<cmdalt> Wizard::get_Battle_alternatives()
{
	std::vector<cmdalt> alternatives;
		{
		// attack
		cmdalt alt;
		alt.first = "attack";
		
		alt.second = {};
		alternatives.push_back(alt);
	}	
	{
		// collect
		cmdalt alt;
		alt.first = "collect";
		alt.second = {"mana"};
		alternatives.push_back(alt);
	}
	{
		// check status
		cmdalt alt;
		alt.first = "check";
		alt.second = {"status", "enemy"};
		alternatives.push_back(alt);
	}
	{
		// run away
		cmdalt alt;
		alt.first = "run";
		alt.second = {"away"};
		alternatives.push_back(alt);
	}
	{
		// run away
		cmdalt alt;
		alt.first = "help";
		alt.second = {};
		alternatives.push_back(alt);
	}
	return alternatives;
}


void Wizard::updateMag(int change){
	mag += change;
}

void Wizard::setInitialAttributes()
{
	HP = 10;
	maxHP = 10;
	def = 5;
	mag = 100;
	magDef = 10;
	mana = 100;
	maxMana = 100;
}

void Wizard::addMag(int change)
{
	mag += change;
}



void Wizard::addMaxMana(int change)
{
	maxMana += change;
}

bool Wizard::updateMana(int change){
	mana += change;
	if(mana > maxMana) mana = maxMana;
		if(mana <= 0){
			printf("Mana is lower then zero, this should not happen");
		}
	return true;
}

std::string Wizard::getType()
{
	return "Wizard";
}

void Wizard::updateMaxMana(int change){
	maxMana += change;
}
int Wizard::getMana(){
	return mana;
}

int Wizard::getMaxMana(){
	return maxMana + getBonus(3);
}

int Wizard::getMag(){
	return mag + getBonus(2);
}



void Wizard::levelUp()
{
	level += 1;
	if(level > 1){
		addMaxHP(10);
		addHP(10);
		addDef(10);
		addMag(10);
		updateMana(10);
		addMaxMana(10);
	}
	// TODO something more here... change other stuff
}

bool Wizard::equippable(Item& item)
{
	return true; // TODO probably should be more restrictive
}

